/*
 * $Id: stdlib.c 141 2011-10-28 06:48:55Z hyunghwan.chung $
 *
   Copyright 2005-2009 Chung, Hyung-Hwan.

   Licensed under the Apache License, Version 2.0 (the "License");
   you may not use this file except in compliance with the License.
   You may obtain a copy of the License at

       http://www.apache.org/licenses/LICENSE-2.0

   Unless required by applicable law or agreed to in writing, software
   distributed under the License is distributed on an  BASIS,
   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   See the License for the specific language governing permissions and
   limitations under the License.
 */

#include <xp/bas/stdlib.h>
#include <xp/bas/string.h>

#ifdef _MSC_VER
#pragma warning(disable:4244)
#pragma warning(disable:4018)
#endif

int xp_digtoi (xp_char_t c, int base)
{
	if (c >= XP_CHAR('0') && c <= XP_CHAR('9')) {
		c = c - XP_CHAR('0');
	}
	else if (c >= XP_CHAR('A') && c <= XP_CHAR('Z')) {
		c = c - XP_CHAR('A') + 10;
	}
	else if (c >= XP_CHAR('a') && c <= XP_CHAR('z')) {
		c = c - XP_CHAR('a') + 10;
	}
	else return base;

	return (c < base)? c: base;
}

xp_size_t xp_bytetostr_upper (xp_byte_t byte,
	xp_char_t* buf, xp_size_t size, int base, xp_char_t fill)
{
	xp_char_t tmp[(XP_SIZEOF(xp_byte_t) * 8)];
	xp_char_t* p = tmp, * bp = buf, * be = buf + size - 1;

	if (base < 2 || base > 36 || size <= 0) return 0;

	do {
		xp_byte_t digit = byte % base;	
		if (digit < 10) *p++ = digit + XP_CHAR('0');
		else *p++ = digit + XP_CHAR('A') - 10;
		byte /= base;
	} while (byte > 0);

	if (fill != XP_CHAR('\0')) {
		while (size - 1 > p - tmp) {
			*bp++ = fill;
			size--;
		}
	}

	while (p > tmp && bp < be) *bp++ = *--p;
	*bp = XP_CHAR('\0');
	return bp - buf;
}

xp_size_t xp_bytetostr_lower (xp_byte_t byte, 
	xp_char_t* buf, xp_size_t size, int base, xp_char_t fill)
{
	xp_char_t tmp[(XP_SIZEOF(xp_byte_t) * 8) + 1];
	xp_char_t* p = tmp, * bp = buf, * be = buf + size - 1;

	if (base < 2 || base > 36 || size <= 0) return 0;

	do {
		xp_byte_t digit = byte % base;	
		if (digit < 10) *p++ = digit + XP_CHAR('0');
		else *p++ = digit + XP_CHAR('a') - 10;
		byte /= base;
	} while (byte > 0);
	
	if (fill != XP_CHAR('\0')) {
		while (size - 1 > p - tmp) {
			*bp++ = fill;
			size--;
		}
	}

	while (p > tmp && bp < be) *bp++ = *--p;
	*bp = XP_CHAR('\0');
	return bp - buf;
}

xp_size_t xp_uint16tostr_upper (
	xp_uint16_t value, xp_char_t* buf, xp_size_t size, int base, xp_char_t fill)
{
	xp_char_t tmp[(XP_SIZEOF(xp_uint16_t) * 8)];
	xp_char_t* p = tmp, * bp = buf, * be = buf + size - 1;

	if (base < 2 || base > 36 || size <= 0) return 0;

	do 
	{
		xp_uint16_t digit = value % base;
		if (digit < 10) *p++ = digit + XP_T('0');
		else *p++ = digit + XP_T('A') - 10;
		value /= base;
        } 
	while (value > 0);

	if (fill != XP_T('\0')) 
	{
		while (size - 1 > p - tmp) 
		{
			*bp++ = fill;
			size--;
		}
	}

	while (p > tmp && bp < be) *bp++ = *--p;
	*bp = XP_T('\0'); 
	return bp - buf;
}

xp_size_t xp_uint16tostr_lower (
	xp_uint16_t value, xp_char_t* buf, xp_size_t size, int base, xp_char_t fill)
{
	xp_char_t tmp[(XP_SIZEOF(xp_uint16_t) * 8)];
	xp_char_t* p = tmp, * bp = buf, * be = buf + size - 1;

	if (base < 2 || base > 36 || size <= 0) return 0;

	do 
	{
		xp_uint16_t digit = value % base;
		if (digit < 10) *p++ = digit + XP_T('0');
		else *p++ = digit + XP_T('a') - 10;
		value /= base;
        } 
	while (value > 0);

	if (fill != XP_T('\0')) 
	{
		while (size - 1 > p - tmp) 
		{
			*bp++ = fill;
			size--;
		}
	}

	while (p > tmp && bp < be) *bp++ = *--p;
	*bp = XP_T('\0'); 
	return bp - buf;
}

int xp_atoi (const xp_char_t* str)
{
	int v;
	XP_STRTOI (v, str, XP_NULL, 10);
	return v;
}

long xp_atol (const xp_char_t* str)
{
	long v;
	XP_STRTOI (v, str, XP_NULL, 10);
	return v;
}

xp_int_t xp_strtoint (const xp_char_t* str)
{
	xp_int_t v;
	XP_STRTOI (v, str, XP_NULL, 10);
	return v;
}

xp_long_t xp_strtolong (const xp_char_t* str)
{
	xp_long_t v;
	XP_STRTOI (v, str, XP_NULL, 10);
	return v;
}

xp_uint_t xp_strtouint (const xp_char_t* str)
{
	xp_uint_t v;
	XP_STRTOI (v, str, XP_NULL, 10);
	return v;
}

xp_ulong_t xp_strtoulong (const xp_char_t* str)
{
	xp_ulong_t v;
	XP_STRTOI (v, str, XP_NULL, 10);
	return v;
}

xp_real_t xp_strtoreal (const xp_char_t* str)
{
	/* TODO: implement this */
	return 0.0;
}

xp_size_t xp_inttostr (xp_int_t x, int base, xp_char_t* buf)
{
	xp_size_t outlen;
	XP_ITOSTR (xp_int_t, x, base, buf, &outlen);
	return outlen;
}

xp_size_t xp_longtostr (xp_long_t x, int base, xp_char_t* buf)
{
	xp_size_t outlen;
	XP_ITOSTR (xp_long_t, x, base, buf, &outlen);
	return outlen;
}

xp_size_t xp_uinttostr (xp_uint_t x, int base, xp_char_t* buf)
{
	xp_size_t outlen;
	XP_ITOSTR (xp_uint_t, x, base, buf, &outlen);
	return outlen;
}

xp_size_t xp_ulongtostr (xp_ulong_t x, int base, xp_char_t* buf)
{
	xp_size_t outlen;
	XP_ITOSTR (xp_ulong_t, x, base, buf, &outlen);
	return outlen;
}

xp_size_t xp_sizetostr (xp_size_t x, int base, xp_char_t* buf)
{
	xp_size_t outlen;
	XP_ITOSTR (xp_size_t, x, base, buf, &outlen);
	return outlen;
}
